<template>
  <view class="popup-mask" v-if="isOta" :catchtouchmove="true">
    <view class="popup-container" @click.stop>
      <view class="popup-content">
        <view class="search-box">ota升级中</view>
        <view class="image">
          <image src="../../static/images/longing.gif" mode=""></image>
        </view>
        <view class="progress">当前进度{{ otaData.progressRate }}%</view>
      </view>
    </view>
  </view>
</template>

<script>
import BluetoothManager from '@/utils/BluetoothManager'
import EventManager from '@/utils/eventManager.js'
import { getInfo, download } from '@/api/device'
import { readFileContent } from '@/utils/bleParser.js'
import { crc32CalByByte } from '../../utils/crc32'
import { mapGetters } from 'vuex'
export default {
  name: 'Ota',
  data() {
    return {
      otaData: {
        serviceId: '02F00000-0000-0000-0000-00000000FE00',
        readUuid: '02F00000-0000-0000-0000-00000000FF02',
        writeUuid: '02F00000-0000-0000-0000-00000000FF01',
        imageBaseAddress: 0, // 用于记录设备升级程序的存储起始地址
        currentEraseAddress: 0, //擦拭进度位置
        eraseIndex: 0, //擦拭次数
        packetSize: 500, //默认升级长度
        progress: 0, //升级进度
        progressRate: 0, //升级百分比
      },
      isOta: false,
      isDowanload: false,
      updateFileData: null,
      otaDataView: null,
      updatePackInfo: {},
    }
  },
  computed: {
    ...mapGetters({
      batteryData: 'battery/batteryData',
    }),
  },
  watch: {
    isOta(newVal) {
      if (!newVal) {
        this.clearOtaData()
      }
    },
  },
  mounted() {
    this.getPackInfo()
    // this.dowanload()
    EventManager.addListener('onBLECharacteristicValueChangeOta', (res) => {
      // console.log('ota 回调', res)
      this.handleBLEData(res)
    })
  },
  methods: {
    getPackInfo() {
      getInfo({ params: { id: 16 } }).then((res) => {
        const { data } = res
        this.updatePackInfo = data
      })
    },
    startOta() {
      //判断版本号
      if (!this.updatePackInfo?.ble_version) {
        uni.showModal({
          title: '提示',
          content: '未获取到版本信息!',
          showCancel: false,
          success: function (res) {
            if (res.confirm) {
              console.log('用户点击确定')
            } else if (res.cancel) {
              console.log('用户点击取消')
            }
          },
        })
        return
      }
      //比较版本号
      if (this.updatePackInfo?.ble_version == this.batteryData.softwareVersion) {
        uni.showModal({
          title: '提示',
          content: '当前已经是最新版本!',
          showCancel: false,
          success: function (res) {
            if (res.confirm) {
              console.log('用户点击确定')
            } else if (res.cancel) {
              console.log('用户点击取消')
            }
          },
        })
        return
      }
      uni.showModal({
        title: '系统提示',
        content: '您升级软件请保持电量充足和网络良好, 确定升级?',
        success: (res) => {
          if (res.confirm) {
            this.sendGetBaseAddressCommand()
          } else if (res.cancel) {
            console.log('用户点击取消')
          }
        },
      })
    },
    //获取起始地址
    sendGetBaseAddressCommand() {
      this.isOta = true
      var buffer = new ArrayBuffer(7)
      var dataView = new DataView(buffer)
      dataView.setUint8(0, 0x01)
      dataView.setUint16(1, 0x0004)
      console.log('起始地址命令', dataView.buffer)
      this.sendMessage(dataView.buffer)
    },
    // 发送擦除命令
    sendEraseCommand() {
      // 构建命令数据并发送
      let address = this.otaData.currentEraseAddress
      console.log('当前擦拭地址', address)
      var buffer = new ArrayBuffer(7)
      var dataView = new DataView(buffer)
      dataView.setUint8(0, 0x03)
      dataView.setUint16(1, 0x0004)
      dataView.setUint32(3, address, true)
      this.sendMessage(dataView.buffer)
    },
    // 发送写数据命令
    sendWriteDataCommand(index) {
      const otaDataView = this.otaDataView
      const packetSize = this.otaData.packetSize
      const imageBaseAddress = this.otaData.imageBaseAddress
      const start = index * packetSize
      const end = Math.min(start + packetSize, otaDataView.byteLength)
      let totalIndex = Math.ceil(otaDataView.byteLength / packetSize)
      //再次拦截避免超出
      if (index + 1 > totalIndex) {
        console.log('升级完成总次数', index)
        return
      }
      // 从 DataView 中获取指定范围的 Uint8Array
      const packData = new Uint8Array(otaDataView.buffer, start, end - start)
      let packetLength = packData.length
      //起始地址 + 本次提交地址
      let newAddress = imageBaseAddress + index * packetSize
      var buffer = new ArrayBuffer(9 + packetLength)
      var dataView = new DataView(buffer)
      dataView.setUint8(0, 0x05)
      dataView.setUint16(1, 0x09, true)
      dataView.setUint32(3, newAddress, true)
      dataView.setUint16(7, packetLength, true)
      for (let i = 0; i < packetLength; i++) {
        let packetIndex = i + 9
        dataView.setUint8(packetIndex, packData[i])
      }
      console.log(
        `次数: ${index + 1} start:${start} end:${end} 包大小:${packetLength} 本次地址${newAddress}`
      )
      this.sendMessage(dataView.buffer)
    },
    sendUpgradeCompleteCommand() {
      // 构建命令数据并发送
      var buffer = new ArrayBuffer(11)
      var dataView = new DataView(buffer)
      dataView.setUint8(0, 0x09)
      dataView.setUint16(1, 0x0008)
      const otaDataView = this.otaDataView
      dataView.setUint32(3, otaDataView.length, true)
      const packData = new Uint8Array(otaDataView.buffer, 256, otaDataView.length - 256)
      const crc32 = crc32CalByByte(0, packData)
      let crcVal = '0x' + (crc32 >>> 0).toString(16).padStart(8, '0')
      dataView.setUint32(7, crcVal, true)
      this.isOta = false
      console.log('升级完成命令发送')
      this.sendMessage(dataView.buffer)
    },
    sendMessage(buffer) {
      BluetoothManager.sendOtaCommand(
        this.batteryData.deviceId,
        this.otaData.serviceId,
        this.otaData.writeUuid,
        buffer
      ).then((res) => {
        if (!this.isOta) {
          uni.showModal({
            title: '提示',
            content: '升级已完成请重新连接设备!',
            showCancel: false,
            success: function (res) {
              if (res.confirm) {
                console.log('用户点击确定')
              } else if (res.cancel) {
                console.log('用户点击取消')
              }
            },
          })
        }
      })
    },
    dowanload() {
      //判断软件包区分版本
      var packageStr = this.getPackageBinStr(
        this.batteryData.hardwareVersion,
        this.batteryData.softwareVersion
      )

      console.log('下载地址', packageStr)
      //下载文件
      download(packageStr).then((res) => {
        readFileContent(res.tempFilePath).then((res) => {
          console.log(res)
          let dataView = new Uint8Array(res)
          this.otaDataView = dataView
          console.log('文件长度' + this.otaDataView.length)
          this.isDowanload = true
          //开始擦拭命令
          this.sendEraseCommand()
        })
      })
    },
    getPackageBinStr(hardwareVersion, softwareVersion) {
      let versionDate = this.getVersionYearDate(softwareVersion)
      console.log('版本号日期', softwareVersion, versionDate)
      //判断硬件版本
      let hardwareStr = hardwareVersion.substring(0, 3).toUpperCase()
      if (hardwareStr == 'JJC') {
        // 判断软件版本
        if (versionDate < '20241230') {
          return 'package_16_backup_package_2.bin'
        }
        return 'package_16_software_package.bin'
      } else {
        if (versionDate < '20241230') {
          return 'package_16_backup_package_1.bin'
        }
        return 'package_16_ble_package.bin'
      }
    },
    getVersionYearDate(version) {
      // VB_2025_01_01_01
      let arr = version.split('_')
      if (arr.length == 5) {
        return arr[1] + '' + arr[2] + '' + arr[3]
      } else {
        return '20250101'
      }
    },

    clearOtaData() {
      this.otaData = {
        serviceId: '02F00000-0000-0000-0000-00000000FE00',
        readUuid: '02F00000-0000-0000-0000-00000000FF02',
        writeUuid: '02F00000-0000-0000-0000-00000000FF01',
        imageBaseAddress: 0, // 用于记录设备升级程序的存储起始地址
        currentEraseAddress: 0, //擦拭进度位置
        eraseIndex: 0, //擦拭次数
        packetSize: 500, //默认升级长度
        progress: 0, //升级进度
        progressRate: 0, //升级百分比
      }
    },
    handleBLEData(characteristic) {
      if (characteristic.characteristicId != this.otaData.readUuid) {
        console.log('不是ota不处理...')
        return
      }
      let val = characteristic.value
      let data = new Uint8Array(val)
      let dataView = new DataView(val)
      const command = data[1] // 获取命令字节
      const res = data[0]
      console.log('回调命令:' + command)
      if (res) {
        console.log('返回失败信息', data)
        return
      }
      // console.log('回调信息', data)
      switch (command) {
        case 0x01:
          // 处理获取升级起始地址的返回数据
          // 更新 imageBaseAddress
          let address = dataView.getInt32(4, true)
          console.log('起始位置', address)
          this.otaData.imageBaseAddress = address
          this.otaData.currentEraseAddress = address
          this.otaData.eraseIndex = 0
          this.otaData.progress = 0
          this.otaData.progressRate = 0
          if (!this.isDowanload) {
            this.dowanload()
          }
          break
        case 0x02:
          // 处理获取软件版本号的返回数据
          break
        case 0x03:
          // 处理擦除命令的返回数据
          let resAddress = dataView.getInt32(4, true)
          const eraseIndex = this.otaData.eraseIndex + 1
          console.log('擦拭地址' + eraseIndex, resAddress)
          if (resAddress - this.otaData.imageBaseAddress < this.otaDataView.length) {
            this.otaData.currentEraseAddress = resAddress + 4096
            this.otaData.eraseIndex = eraseIndex
            this.sendEraseCommand()
          } else {
            console.log('擦拭结束----开始升级', resAddress)
            //准备升级
            this.sendWriteDataCommand(0)
          }
          break
        case 0x05:
          // 处理写数据命令的返回数据
          const otaDataView = this.otaDataView
          const packetSize = this.otaData.packetSize
          let totalIndex = Math.ceil(otaDataView.byteLength / packetSize)
          let progress = this.otaData.progress + 1
          let progressRate = Math.floor(Number(progress / totalIndex).toFixed(2) * 100)
          progressRate = progressRate < 100 ? progressRate : 100
          console.log('完成上传:' + progress + '总次数:' + totalIndex)
          if (progress >= totalIndex) {
            //上传完成
            console.log('上传完成----准备重启', progress)
            this.sendUpgradeCompleteCommand()
          } else {
            this.otaData.progress = progress
            this.otaData.progressRate = progressRate
            this.sendWriteDataCommand(progress)
          }
          break
        case 0x09:
          console.log('重启回调了')
          // 处理升级完成命令的返回数据
          break
        // 其他命令的处理...
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.popup-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 99999;
}

.popup-container {
  background-color: #fff;
  width: 80%;
  padding: 24rpx;
  border-radius: 10px;
  overflow: hidden;
}

.popup-content {
  padding: 20px;
}

.search-box {
  width: 100%;
  display: flex;
  justify-content: center;
  font-family: MicrosoftYaHei;
  font-size: 41rpx;
}
.search-box .search-btn {
  width: calc(100% - 178rpx);
  height: 78rpx;
  text-align: center;
  line-height: 77rpx;
  background: #574166;
  color: #ffffff;
  border-radius: 5rpx 5rpx 5rpx 5rpx;
}
.search-box .search-cancel {
  width: 158rpx;
  height: 76rpx;
  line-height: 78rpx;
  text-align: center;
  // background: #3a2b44;
  border-radius: 5rpx 5rpx 5rpx 5rpx;
  border: 1px solid #3a2b44;
  color: #3a2b44;
}
.popup-actions {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid #574166;
}
.image {
  width: 100%;
  text-align: center;
  image {
    width: 160rpx;
    height: 160rpx;
    margin: auto;
  }
}

.progress {
  width: 100%;
  text-align: center;
}
</style>
